<?php

namespace app\core\services\user;

use app\core\entities\User;
use app\core\forms\user\UserForm;
use app\core\repositories\user\UserRepository;
use app\core\services\RoleManager;
use app\core\services\TransactionManager;
use Throwable;
use yii\base\Exception;
use yii\db\StaleObjectException;

class UserManageService
{
    private UserRepository $user_repository;
    private RoleManager $roles;
    private TransactionManager $transaction;

    /**
     * UserManageService constructor.
     *
     * @param UserRepository $user_repository
     * @param RoleManager $roles
     * @param TransactionManager $transaction
     */
    public function __construct(
        UserRepository $user_repository,
        RoleManager $roles,
        TransactionManager $transaction
    )
    {
        $this->user_repository  = $user_repository;
        $this->roles       = $roles;
        $this->transaction = $transaction;
    }

    /**
     * @throws \yii\db\Exception
     * @throws Exception
     */
    public function create(UserForm $form): User
    {
        $user = User::create(
            $form->username,
            $form->email,
            $form->password
        );
        $this->transaction->wrap(function () use ($user, $form) {
            $this->user_repository->save($user);
            $this->roles->assign($user->id, $form->role);
        });
        return $user;
    }

    /**
     * @throws Exception
     * @throws \yii\db\Exception
     */
    public function edit($id, UserForm $form): void
    {
        $user = $this->user_repository->get($id);
        $user->edit(
            $form->username,
            $form->email,
            $form->password
        );
        $this->transaction->wrap(function () use ($user, $form) {
            $this->user_repository->save($user);
            $this->roles->assign($user->id, $form->role);
        });
    }

    /**
     * @throws \Exception
     */
    public function assignRole($id, $role): void
    {
        $user = $this->user_repository->get($id);
        $this->roles->assign($user->id, $role);
    }

    /**
     * @throws StaleObjectException|Throwable
     */
    public function remove($id): void
    {
        $user = $this->user_repository->get($id);
        $this->user_repository->remove($user);
    }

    public function setSetting($id, $key, $value): void
    {
        $user = $this->user_repository->get($id);
        $settings = $user->settings ? json_decode($user->settings, true) : [];
        $settings[$key] = $value;
        $user->settings = json_encode($settings, JSON_UNESCAPED_UNICODE);
        $this->user_repository->save($user);
    }
}
